﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Globalization;
using System.Reflection;
using System.IO;

namespace ExchangeCurrencyRate.Entity
{
    /// <summary>
    /// This is abstract class. All Currency Rate providers should instantiate this class.
    /// </summary>
    public abstract class CurrencyRateProvider
    {
        /// <summary>
        /// Get <see cref="ExchangeCurrencyRate.Entity.CurrencyRateProvider"/> registered in config file.
        /// </summary>
        /// <remarks>
        /// Do not forget register provider in .config file.
        /// &lt;appSettings&gt;
        ///   ...
        ///   &lt;add key="currencyProviderAssembly" value="..."/&gt;
        ///   &lt;add key="currencyProviderType" value="..."/&gt;
        ///   ...
        /// &lt;/appSettings&gt;
        /// </remarks>
        /// <returns><see cref="ExchangeCurrencyRate.Entity.CurrencyRateProvider"/> instance</returns>
        public static CurrencyRateProvider GetProvider()
        {
            string providerAssemblyFile = ConfigurationManager.AppSettings["currencyProviderAssembly"];
            string providerTypeName = ConfigurationManager.AppSettings["currencyProviderType"];
            string searchDir = AppDomain.CurrentDomain.RelativeSearchPath;
            Assembly assembly = Assembly.LoadFile(
                Path.Combine(searchDir, providerAssemblyFile));
            Type providerType = assembly.GetType(providerTypeName);
            return (CurrencyRateProvider)Activator.CreateInstance(providerType);
        }
        /// <summary>
        /// Return exchange rate for given currencies and date.
        /// </summary>
        /// <param name="fromCurrencyCode">First currency</param>
        /// <param name="toCurrencyCode">Second currency</param>
        /// <param name="dateTime">Date</param>
        /// <returns>Return <see cref="ExchangeCurrencyRate.Entity.ExchangeRate"/></returns>
        public abstract ExchangeRate GetExchangeRate(string fromCurrencyCode, string toCurrencyCode, DateTime dateTime);
        /// <summary>
        /// Save Exchange Rate to storage
        /// </summary>
        /// <param name="exchangeRate">Exchnage Rate object</param>
        /// <returns>Returns status</returns>
        public virtual bool SaveExchangeRate(ExchangeRate exchangeRate)
        {
            return SaveExchangeRate(exchangeRate.CurrencyFrom, exchangeRate.CurrencyTo, exchangeRate.Date, exchangeRate.Rate);
        }
        /// <summary>
        /// Save Exchange Rate to storage
        /// </summary>
        /// <param name="fromCurrencyCode">First currency code</param>
        /// <param name="toCurrencyCode">Second currency code</param>
        /// <param name="dateTime">DateTime</param>
        /// <param name="exchangeRate">Currency exchange rate</param>
        /// <returns>Returns status</returns>
        public abstract bool SaveExchangeRate(string fromCurrencyCode, string toCurrencyCode, DateTime dateTime, decimal exchangeRate);
        /// <summary>
        /// Check if Currency code valid
        /// </summary>
        /// <param name="currencyCode">Currency code</param>
        /// <returns>True if currency code valid, False otherwise.</returns>
        public virtual bool CheckCurrencyCode(string currencyCode)
        {
            foreach (CultureInfo culture in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.InstalledWin32Cultures))
            {
                try
                {
                    RegionInfo region = new System.Globalization.RegionInfo(culture.LCID);
                    if (String.Equals(region.ISOCurrencySymbol, currencyCode, StringComparison.InvariantCultureIgnoreCase))
                    {
                        return true;
                    }
                }
                catch (Exception)
                {
                    continue;
                }
            }
            return false;
        }
    }
}
